/**
 * creation: 17-apr-2007
 */
package org.jfonia.structure;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jfonia.connect.ListElement;
import org.jfonia.connect.Node;
import org.jfonia.connect.SafeListElement;
import org.jfonia.connect.SimpleValue;
import org.jfonia.connect.Value;
import org.jfonia.connect.logic.IntLessThanOrEqual;
import org.jfonia.connect.logic.LogicalAnd;
import org.jfonia.connect.logic.While;


/**
 * @author Wijnand
 *
 */
public class IndexedFamily implements Family
{
	private Map<String, Object> listMap = new HashMap<String, Object>();
	private int size;
	
	
	public int getSize()
	{
		return size;
	}

	public void setSize(int size)
	{
		this.size = size;
	}

	public void putList(String id, Object list)
	{
		int listSize = 0;
		if (list instanceof List)
			listSize = ((List)list).size();
//		else if (list instanceof ArrayListForInt)
//			listSize = ((ArrayListForInt)list).size();
//		else if (list instance of array...) ...
		else	
			throw new RuntimeException("list type '" + list.getClass() + "' not supported");
		
		if (this.listMap.isEmpty())
			this.size = listSize;
		else {
			if (this.size != listSize)
				System.out.println("warning: list-size and family-size don't match. Using smallest size for family."); // TODO: use Logger
			this.size = Math.min(this.size, listSize);
		}
		listMap.put(id, list);
		
	}
	
	public Object getList(String id)
	{
		return listMap.get(id);
	}
	
	public void removeList(String id)
	{
		listMap.remove(id);
	}

	// ------ connect stuff: ------
	
	public Value<Integer> getSizeValue()
	{
		return new SimpleValue<Integer>(size);
	}
	
//	public Slice createSlice(String id) 
//	{
//		List lst = (List<Integer>)getList(id);
//		return new IndexSlice(this, 
//				              createIndexIterator(lst.size()),
//				              lst);	// TODO... if not List...
//	}
	
	public Slice createSlice() 
	{
		return new IndexSlice(this, createIndexIterator(this.size));	
	}

	public IntIterator createIndexIterator(int size)
	{
//		System.out.println("creating index iterator. size=" + size);
		return new TrivialIntIterator(-1, size);
	}

	public Value getProperty(String id, Value<Integer> index)
	{
		Object list = listMap.get(id);
		if (list==null)
			throw new RuntimeException("Unknown list '" + id + "'");
		if (list instanceof List)
			return new ListElement((List)list, index);	
					// TODO: check index boundaries?
					// TODO: special prov for -infty and infty?
//		else if (list instanceof ArrayListForInt)
//			return new IndexedMutableElementForInt(new ArrayListAccessorForInt((ArrayListForInt)list), indexElement);
		else
			throw new RuntimeException("list type '" + list.getClass()+ "' not supported");
	}

	public boolean hasProperty(String id)
	{
		return listMap.containsKey(id);
	}

	public Value<Integer> getKey(String id, Value<Integer> index) 
	{
		Object list = listMap.get(id);
		if (list==null)
			throw new RuntimeException("Unknown list '" + id + "'");
		if (list instanceof List)
			return new SafeListElement((List)list, index);	
		else
			throw new RuntimeException("list type '" + list.getClass()+ "' not supported");
	}
	

	// TODO: allow specialization for fast indexing (in IndexedFamily or here ??)
	// TODO: here or in IndexSlice??
	public Node getFastForwarder(String id, Value<Integer> target, IntIterator indexIterator)
	{
		return new While(new LogicalAnd(indexIterator.getProceedCondition(), 
                                        new IntLessThanOrEqual(getProperty(id, indexIterator.getLookaheadValue()), 
                                        		               target ) ), 
                		 indexIterator.getProceeder());
	}

	
}
